package com.admin.system.modules.oauth.service;

import com.admin.common.constant.Constant;
import com.admin.common.enums.DataScopeEnum;
import com.admin.common.exception.BadRequestException;
import com.admin.common.utils.StringUtils;
import com.admin.core.entity.*;
import com.admin.core.mapper.RoleDeptMapper;
import com.admin.core.mapper.RoleMenuMapper;
import com.admin.oauth.dto.LoginUserDto;
import com.admin.system.modules.system.service.DeptService;
import com.admin.system.modules.system.service.MenuService;
import com.admin.system.modules.system.service.RoleService;
import com.admin.system.modules.system.service.UserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author sq-lan
 */
@Slf4j
@RequiredArgsConstructor
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

    private final UserService userService;
    private final DeptService deptService;
    private final RoleService roleService;
    private final MenuService menuService;
    private final RoleDeptMapper roleDeptMapper;
    private final RoleMenuMapper roleMenuMapper;

    @Override
    public LoginUserDto loadUserByUsername(String username) {
        LambdaQueryWrapper<SysUser> wrapper = Wrappers.<SysUser>lambdaQuery()
                .select(SysUser::getAvatarName, SysUser::getAvatarPath, SysUser::getDeptId,
                        SysUser::getEmail, SysUser::getEnabled, SysUser::getGender,
                        SysUser::getId, SysUser::getIsAdmin, SysUser::getPassword,
                        SysUser::getPhone, SysUser::getUsername, SysUser::getNickName)
                .eq(SysUser::getUsername, username);
        SysUser user = userService.getOne(wrapper, false);
        if (user == null) {
            throw new BadRequestException("用户名或密码不正确");
        }
        if (!user.getEnabled()) {
            throw new BadRequestException("账号未激活！");
        }

        SysDept dep = deptService.getOne(Wrappers.<SysDept>lambdaQuery().select(SysDept::getId, SysDept::getName).eq(SysDept::getId, user.getDeptId()));
        user.setDept(dep);
        List<SysRole> roles = roleService.listByUsersId(user.getId());
        user.setRoles(roles);
        Set<String> permissions = permissions(user);
        return new LoginUserDto(user, listDataScope(user, roles), null, permissions);
    }

    /**
     * 角色分配的数据权限
     */
    public Set<Integer> listDataScope(SysUser user, List<SysRole> roleList) {
        // 存储部门id
        Set<Integer> deptIds = new HashSet<>();
        if (user.getIsAdmin()) {
            return deptIds;
        }
        // 用户角色
        if (roleList == null || roleList.isEmpty()) {
            return deptIds;
        }
        // 获取对应的部门ID
        for (SysRole role : roleList) {
            if (role.getDataScope() == null) {
                continue;
            }
            DataScopeEnum dataScopeEnum = DataScopeEnum.getByValue(role.getDataScope());
            switch (Objects.requireNonNull(dataScopeEnum)) {
                case SELF:
                case DEPT:
                    deptIds.add(user.getDeptId());
                    break;
                case DEPT_AND_CHILD:
                    List<SysDept> deps = new ArrayList<>();
                    deps.add(user.getDept());
                    deptService.recursionChildId(deps, deptIds);
                    break;
                case CUSTOMIZE:
                    List<SysRoleDept> roleDeptList = roleDeptMapper.selectList(Wrappers.<SysRoleDept>lambdaQuery().select(SysRoleDept::getDeptId).eq(SysRoleDept::getRoleId, role.getId()));
                    List<Integer> ids = roleDeptList.stream().map(SysRoleDept::getDeptId).collect(Collectors.toList());
                    deptIds.addAll(ids);
                    break;
                default:
                    return deptIds;
            }
        }
        return deptIds;
    }

    /**
     * 获取用户权限信息
     */
    public Set<String> permissions(SysUser user) {
        Set<String> permissions = new HashSet<>();
        // 如果是管理员直接返回
        if (user.getIsAdmin()) {
            permissions.add(Constant.ADMIN);
            return permissions;
        }
        List<SysRole> roles = user.getRoles();
        Set<Integer> roleIdSet = roles.stream().map(SysRole::getId).collect(Collectors.toSet());
        List<SysRoleMenu> roleMenus = roleMenuMapper.selectList(Wrappers.<SysRoleMenu>lambdaQuery().select(SysRoleMenu::getMenuId).in(SysRoleMenu::getRoleId, roleIdSet));
        Set<Integer> menuIds = roleMenus.stream().map(SysRoleMenu::getMenuId).collect(Collectors.toSet());
        List<SysMenu> menus = menuService.list(Wrappers.<SysMenu>lambdaQuery().select(SysMenu::getPermission).in(SysMenu::getId, menuIds).isNotNull(SysMenu::getPermission));

        permissions = menus.stream().map(SysMenu::getPermission).filter(StringUtils::isNotBlank).collect(Collectors.toSet());
        return permissions;
    }

}
